package jmars.mobile.worker;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import jmars.mobile.common.Investigator;
import jmars.mobile.datainvestigation.Summary;

/**
 * 2012.11.16 20:01 Friday - 2012.11.23 04:59 Friday 17~22
 * 2012.10.26 23:00 Friday - 2012.10.28 01:59 Sunday 27
 * detect the active rate for each interval. workday
 * groupKey means the identity of user = 0
 * @author Jan
 *
 */
public class ActiveUserRateWorkday implements Investigator {

	int[] workdays = {19,20,21,22};
	int[] processDays = {19};

	private Long computeAll(File[] files,FileWriter writer) throws IOException{
		Long total = 0L;
		Long line;
		int filesFinished=0;
		FileInputStream fis;
		BufferedReader reader;
		String row;
		String[] cols;
		Set<String> users=new HashSet<String>();
//		Map<Integer,Map<Long,Set<String>>> fiveMinutesActive = new HashMap<Integer,Map<Long,Set<String>>>();
//		Map<Integer,Map<Long,Integer>> fiveMinutesActiveS = new HashMap<Integer,Map<Long,Integer>>();
		Map<Integer,Map<Long,Set<String>>> tenMinutesActive = new HashMap<Integer,Map<Long,Set<String>>>();
		Map<Integer,Map<Long,Integer>> tenMinutesActiveS = new HashMap<Integer,Map<Long,Integer>>();
//		Map<Integer,Map<Long,Set<String>>> twentyMinutesActive = new HashMap<Integer,Map<Long,Set<String>>>();
//		Map<Integer,Map<Long,Integer>> twentyMinutesActiveS = new HashMap<Integer,Map<Long,Integer>>();
//		Map<Integer,Map<Long,Set<String>>> aQuarterActive = new HashMap<Integer,Map<Long,Set<String>>>();
//		Map<Integer,Map<Long,Integer>> aQuarterActiveS = new HashMap<Integer,Map<Long,Integer>>();
		Map<Integer,Map<Long,Set<String>>> halfActive = new HashMap<Integer,Map<Long,Set<String>>>();
		Map<Integer,Map<Long,Integer>> halfActiveS = new HashMap<Integer,Map<Long,Integer>>();
		Map<Integer,Map<Long,Set<String>>> hourActive = new HashMap<Integer,Map<Long,Set<String>>>();
		Map<Integer,Map<Long,Integer>> hourActiveS = new HashMap<Integer,Map<Long,Integer>>();
		for(int day:processDays){
//			fiveMinutesActive.put(day, new HashMap<Long,Set<String>>());
//			fiveMinutesActiveS.put(day, new HashMap<Long,Integer>());
			tenMinutesActive.put(day, new HashMap<Long,Set<String>>());
			tenMinutesActiveS.put(day, new HashMap<Long,Integer>());
//			twentyMinutesActive.put(day, new HashMap<Long,Set<String>>());
//			twentyMinutesActiveS.put(day, new HashMap<Long,Integer>());
//			aQuarterActive.put(day, new HashMap<Long,Set<String>>());
//			aQuarterActiveS.put(day, new HashMap<Long,Integer>());
			halfActive.put(day, new HashMap<Long,Set<String>>());
			halfActiveS.put(day, new HashMap<Long,Integer>());
			hourActive.put(day, new HashMap<Long,Set<String>>());
			hourActiveS.put(day, new HashMap<Long,Integer>());
		}
		Calendar cal=Calendar.getInstance();
		Date beginDate;
		Long time;
		Long day;
		String groupKey;
		File inputFile;
		for(int fIndex=0;fIndex<files.length;fIndex++){
			inputFile=files[fIndex];
			fis = new FileInputStream(inputFile);
			reader = new BufferedReader(new InputStreamReader(fis));
			line=0L;
			while((row=reader.readLine())!=null){
				line++;
				try{
					cols=row.split(Summary.columnSeperator);
					if(Summary.filterRowExcludeLACI(cols,true,false)) continue;
					beginDate=Summary.parseBeginDate(cols);
					if(beginDate==null) continue;
					total++;
					cal.setTime(beginDate);
					if(cal.get(Calendar.YEAR)!=2012||(cal.get(Calendar.MONTH)!=10&&cal.get(Calendar.MONTH)!=11)) continue;
					if(cal.get(Calendar.DAY_OF_MONTH)!=19)continue;
					if(tenMinutesActive.containsKey(cal.get(Calendar.DAY_OF_MONTH))){
						groupKey=Summary.genGroupKey(cols);
						users.add(groupKey);
						day=beginDate.getTime()%(24*60*60*1000);
//						time=day-day%(5*60*1000);
//						if(!fiveMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).containsKey(time))
//							fiveMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).put(time,new HashSet<String>());
//						fiveMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).get(time).add(groupKey);
//						aggActiveS(cal,time,fiveMinutesActive,fiveMinutesActiveS,fIndex==files.length-1);
						time=day-day%(10*60*1000);
						if(!tenMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).containsKey(time))
							tenMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).put(time,new HashSet<String>());
						tenMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).get(time).add(groupKey);
						aggActiveS(cal,time,tenMinutesActive,tenMinutesActiveS,fIndex==files.length-1);
//						time=day-day%(15*60*1000);
//						if(!aQuarterActive.get(cal.get(Calendar.DAY_OF_MONTH)).containsKey(time))
//							aQuarterActive.get(cal.get(Calendar.DAY_OF_MONTH)).put(time,new HashSet<String>());
//						aQuarterActive.get(cal.get(Calendar.DAY_OF_MONTH)).get(time).add(groupKey);
//						aggActiveS(cal,time,aQuarterActive,aQuarterActiveS,fIndex==files.length-1);
//						time=day-day%(20*60*1000);
//						if(!twentyMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).containsKey(time))
//							twentyMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).put(time,new HashSet<String>());
//						twentyMinutesActive.get(cal.get(Calendar.DAY_OF_MONTH)).get(time).add(groupKey);
//						aggActiveS(cal,time,twentyMinutesActive,twentyMinutesActiveS,fIndex==files.length-1);
						time=day-day%(30*60*1000);
						if(!halfActive.get(cal.get(Calendar.DAY_OF_MONTH)).containsKey(time))
							halfActive.get(cal.get(Calendar.DAY_OF_MONTH)).put(time,new HashSet<String>());
						halfActive.get(cal.get(Calendar.DAY_OF_MONTH)).get(time).add(groupKey);
						aggActiveS(cal,time,halfActive,halfActiveS,fIndex==files.length-1);
						time=day-day%(60*60*1000);
						if(!hourActive.get(cal.get(Calendar.DAY_OF_MONTH)).containsKey(time))
							hourActive.get(cal.get(Calendar.DAY_OF_MONTH)).put(time,new HashSet<String>());
						hourActive.get(cal.get(Calendar.DAY_OF_MONTH)).get(time).add(groupKey);
						aggActiveS(cal,time,hourActive,hourActiveS,fIndex==files.length-1);
					}
				}catch(Exception ex){
					System.out.println("exception at line "+line+" of "+inputFile.getName());
					System.out.println(row);
					ex.printStackTrace();
					if(!Summary.errorResume){
						System.exit(0);
					}
				}
			}
			
			filesFinished++;
			reader.close();
			fis.close();
			System.out.println(filesFinished+": "+inputFile.getName()+" finished at "+line);
		}


		writer.write("total users: "+ Summary.intFormat.format(users.size())+"\r\n");
		writer.write("time,mean%,variance%, standard deviation%\r\n");
		writer.write("******workday active rate********\r\n");
		
//		writer.write("******5 min*******\r\n");
//		Map<Long,Double> workFiveMinutesRateMean = new HashMap<Long,Double>();
//		Map<Long,Double> workFiveMinutesRateVariance = new HashMap<Long,Double>();
//		calMeanVar(fiveMinutesActiveS,users,5*60*1000L,workFiveMinutesRateMean,workFiveMinutesRateVariance,workdays,writer);

		writer.write("******10 min*******\r\n");
		Map<Long,Double> workTenMinutesRateMean = new HashMap<Long,Double>();
		Map<Long,Double> workTenMinutesRateVariance = new HashMap<Long,Double>();
		calMeanVar(tenMinutesActiveS,users,10*60*1000L,workTenMinutesRateMean,workTenMinutesRateVariance,workdays,writer);

//		writer.write("******15 min*******\r\n");
//		Map<Long,Double> work15MinutesRateMean = new HashMap<Long,Double>();
//		Map<Long,Double> work15MinutesRateVariance = new HashMap<Long,Double>();
//		calMeanVar(aQuarterActiveS,users,15*60*1000L,work15MinutesRateMean,work15MinutesRateVariance,workdays,writer);
//
//		writer.write("******20 min*******\r\n");
//		Map<Long,Double> work20MinutesRateMean = new HashMap<Long,Double>();
//		Map<Long,Double> work20MinutesRateVariance = new HashMap<Long,Double>();
//		calMeanVar(twentyMinutesActiveS,users,20*60*1000L,work20MinutesRateMean,work20MinutesRateVariance,workdays,writer);

		writer.write("******30 min*******\r\n");
		Map<Long,Double> work30MinutesRateMean = new HashMap<Long,Double>();
		Map<Long,Double> work30MinutesRateVariance = new HashMap<Long,Double>();
		calMeanVar(halfActiveS,users,30*60*1000L,work30MinutesRateMean,work30MinutesRateVariance,workdays,writer);

		writer.write("******60 min*******\r\n");
		Map<Long,Double> work60MinutesRateMean = new HashMap<Long,Double>();
		Map<Long,Double> work60MinutesRateVariance = new HashMap<Long,Double>();
		calMeanVar(hourActiveS,users,60*60*1000L,work60MinutesRateMean,work60MinutesRateVariance,workdays,writer);

		return total;
	}

	private void aggActiveS(Calendar cal,Long time,Map<Integer,Map<Long,Set<String>>> active,Map<Integer,Map<Long,Integer>> activeS,boolean endFlag){
		HashSet<Long> tempVar=new HashSet<Long>();
		Integer day=cal.get(Calendar.DAY_OF_MONTH);
		for(Long t:active.get(day).keySet()){
			if(time-t>10*60*1000||endFlag){
				if(activeS.containsKey(day) && 
						(!activeS.get(day).containsKey(t) || 
								activeS.get(day).get(t)==0)){
					activeS.get(day).put(t, active.get(day).get(t).size());
				}
				tempVar.add(t);
			}
		}
		for(Long t:tempVar){
			active.remove(t);
		}
	}
	
	private void calMeanVar(Map<Integer,Map<Long,Integer>> data, Set<String> totalUsers, Long interval, Map<Long,Double> mean,Map<Long,Double> var,int[] dayOfMonth,FileWriter writer) throws IOException{
		Double tempSum,tempSqSum,tempCount;
		for(Long t=0L;t<24*60*60*1000;t+=interval){
			tempSum=0D;tempSqSum=0D;tempCount=0D;
			writer.write(Summary.intFormat.format(t));
			for(int i:dayOfMonth){
				if(data.containsKey(i)&&data.get(i).containsKey(t)){
					tempSum+=data.get(i).get(t);
					tempSqSum+=Math.pow((double)data.get(i).get(t)/totalUsers.size(),2);
				}
				tempCount++;
			}
			mean.put(t, (double)tempSum/(tempCount*totalUsers.size()));
			var.put(t, (double)tempSqSum/tempCount-Math.pow(mean.get(t),2));
			writer.write(":"+Summary.threeFloatFormat.format(mean.get(t)*100)+","+Summary.threeFloatFormat.format(var.get(t)*100)+","+Summary.threeFloatFormat.format(Math.sqrt(var.get(t))*100)+"\r\n");
		}
	}
	
	
	
	@SuppressWarnings("unused")
	private void calMeanVar2(Map<Integer,Map<Long,Set<String>>> data, Set<String> totalUsers, Long interval, Map<Long,Double> mean,Map<Long,Double> var,int[] dayOfMonth,FileWriter writer) throws IOException{
		Double tempSum,tempSqSum,tempCount;
		for(Long t=0L;t<24*60*60*1000;t+=interval){
			tempSum=0D;tempSqSum=0D;tempCount=0D;
			writer.write(Summary.intFormat.format(t));
			for(int i:dayOfMonth){
				if(data.containsKey(i)&&data.get(i).containsKey(t)){
					tempSum+=data.get(i).get(t).size();
					tempSqSum+=Math.pow((double)data.get(i).get(t).size()/totalUsers.size(),2);
				}
				tempCount++;
			}
			mean.put(t, (double)tempSum/(tempCount*totalUsers.size()));
			var.put(t, (double)tempSqSum/tempCount-Math.pow(mean.get(t),2));
			writer.write(":"+Summary.threeFloatFormat.format(mean.get(t)*100)+","+Summary.threeFloatFormat.format(var.get(t)*100)+","+Summary.threeFloatFormat.format(Math.sqrt(var.get(t))*100)+"\r\n");
		}
	}
	
	
	@Override
	public Long compute(File[] files, FileWriter writer) throws IOException {
		Long total=0L;
		total=computeAll(files,writer);
		return total;
	}

}
